#include <iostream>
#include <vector>
#include <memory>

using namespace std;

class StrBlob
{
    friend class StrBlobPtr;
public:
    using st = vector<string>::size_type;
    StrBlob():data(make_shared<vector<string>>()){};  //初始化一个空的
    StrBlob(initializer_list<string> l1):data(make_shared<vector<string>>(l1)){};
    // copy constructor
    StrBlob(const StrBlob &sb) : data(std::make_shared<vector<string>>(*sb.data)) {}
    // copy-assignment operators
    StrBlob &operator=(const StrBlob &sb);
    bool empty() { return data->empty(); }
    void push_back(const string &s1) { data->push_back(s1); }
    void pop_back();
    string &front();
    string &back();
    const string &front() const;
    const string &back() const;
    StrBlobPtr begin() { return StrBlobPtr(*this); }
    StrBlobPtr end() { return StrBlobPtr(*this, data->size()); }

private:
    shared_ptr<vector<string>> data;
    void check(st i, const string &msg) const;
};

void StrBlob::check(st i, const string &msg) const
{
    if(i >= data->size())
        throw out_of_range(msg);
}
string &StrBlob::front()
{
    check(0, "front on empty StrBlob");
    return data->front();
}
string &StrBlob::back()
{
    check(0, "back on empty StrBlob");
    return data->back();
}
const string &StrBlob::front() const
{
    check(0, "front on empty StrBlob");
    return data->front();
}
const string &StrBlob::back() const
{
    check(0, "back on empty StrBlob");
    return data->back();
}
void StrBlob::pop_back(){
    check(0, "pop_back on empty StrBlob");
    data->pop_back();
}
StrBlob &StrBlob::operator=(const StrBlob &sb)
{
    data = std::make_shared<vector<string>>(*sb.data);
    return *this;
}

class StrBlobPtr
{
public:
    StrBlobPtr() : curr(0){};
    StrBlobPtr(StrBlob &b1, size_t i=0) : wp(b1.data), curr(i) {};
    string &deref() const;
    StrBlobPtr &incr();
private:
    weak_ptr<vector<string>> wp;
    size_t curr;
    shared_ptr<vector<string>> check(size_t, const string&) const;
};

shared_ptr<vector<string>> StrBlobPtr::check(size_t i,const string &msg) const
{
    auto ret = wp.lock();
    if(!ret)
        throw runtime_error("-");
    if(i >= ret->size())
        throw out_of_range(msg);
    return ret;
}
string &StrBlobPtr::deref() const //相当于*运算符，重载运算符后面再学
{
    auto p = check(curr, "dereference past end");
    return (*p)[curr];
}
StrBlobPtr &StrBlobPtr::incr()
{
    ++curr;
    return *this;
}

int main()
{
    StrBlob b1;
    {
        StrBlob b2 = {"a", "an", "and"};
        b1 = b2;
        b2.push_back("about");
    }
    cout << b1.back() << endl;
    

    return 0;
}
/*在 C++ 中，赋值操作符 = 会被转换为调用赋值运算符函数（如果存在）。对于类类型，编译器会自动生成一个默认的赋值运算符函数，除非你显式地定义了一个。对于你的 StrBlob 类，编译器会生成一个默认的赋值运算符函数，该函数会对类的每个成员执行赋值操作。

在你的 StrBlob 类中，唯一的成员是 shared_ptr<vector<string>> data。当你执行 b1 = b2 时，默认的赋值运算符会对 data 成员执行赋值操作，这实际上是对 shared_ptr 的赋值操作。*/